package service

import (
	"encoding/json"
	"fmt"
	"go-graduation/pb/router"
	"go-graduation/service/cmd/cache"
	"go-graduation/service/internal/data"
	"go-graduation/service/internal/data/PO"
	"strconv"
)

func NewArticle() *article {
	return &article{}
}

type article struct {
}

// GetOneArticleById 根据ID获取某篇文章信息
func (a *article) GetOneArticleById(aid int) (*router.ArticleDetailResponse_Detail, error) {

	var res *router.ArticleDetailResponse_Detail

	if aid == 0 {
		return res, fmt.Errorf("缺少ID参数或者ID要大于0")
	}
	row, err := data.NewArticle().GetOneById(aid)
	if err != nil || row.ID == 0 {
		return res, fmt.Errorf("未找到记录")
	}

	return &router.ArticleDetailResponse_Detail{
		Id:      int64(row.ID),
		Title:   row.Title,
		CatId:   int64(row.CatId),
		Author:  row.Author,
		Content: row.Content,
	}, nil
}

// GetArticleByPage 获取分页数据
func (a *article) GetArticleByPage(page int) ([]*router.ArticleListResponse_Lists, error) {
	pageSize := 15
	pageStart := (page - 1) * pageSize
	rows, err := data.NewArticle().GetListByPage(pageStart, pageSize)
	if err != nil || len(rows) == 0 {
		return nil, fmt.Errorf("未找到记录")
	}

	var ids []int
	for _, row := range rows {
		ids = append(ids, row.ID)
	}

	detailDict, err := a.GetDetail(ids)
	if err != nil {
		return nil, fmt.Errorf("读取数据错误")
	}

	list := make([]*router.ArticleListResponse_Lists, 0)
	for _, p := range rows {
		if item, ok := detailDict[p.ID]; ok {
			list = append(list, &router.ArticleListResponse_Lists{
				Id:      int64(item.ID),
				Title:   item.Title,
				Author:  item.Author,
				Content: item.Content,
				CatId:   int64(item.CatId),
			})
		}
	}

	return list, nil
}

func (a *article) GetDetail(ids []int) (map[int]PO.Article, error) {

	output := make(map[int]PO.Article)

	redis := cache.RedisClient()
	redisKey := "article:detail:hash"

	findDict := make(map[int]PO.Article)
	cacheDict := make(map[int]PO.Article)
	// 转格式
	var idsStrList []string
	for _, id := range ids {
		idStr := strconv.Itoa(id)
		idsStrList = append(idsStrList, idStr)
	}

	// 需要查数据库的ID
	var findSlice []int
	// 获取已缓存的数据
	cacheList, _ := redis.HMGet(redisKey, idsStrList...).Result()
	for key, item := range cacheList {
		id := ids[key]
		// 未设置或已过期
		if item == nil {
			findSlice = append(findSlice, id)
		} else {
			var val PO.Article
			// json 解析错误则重新处理缓存
			if err := json.Unmarshal([]byte(item.(string)), &val); err != nil {
				findSlice = append(findSlice, id)
			}
			cacheDict[id] = val
		}
	}

	if len(findSlice) > 0 {
		// 可以使用hmset，作业要求用pipeline
		findList, _ := data.NewArticle().GetListByIds(findSlice)
		for _, p := range findList {
			findDict[p.ID] = p
		}

		pipe := redis.Pipeline()
		defer func() { _ = pipe.Close() }()
		for _, p := range findDict {
			idStr := strconv.Itoa(p.ID)
			pByte, errJson := json.Marshal(p)
			pStr := string(pByte)
			if errJson != nil {
				pStr = ""
			}
			pipe.HSet(redisKey, idStr, pStr).Val()
		}
		res, errs := pipe.Exec()
		fmt.Println(res, errs)
	}

	// 拼凑数据
	for _, id := range ids {
		if item, ok := findDict[id]; ok {
			output[id] = item
		}
		if item, ok := cacheDict[id]; ok {
			output[id] = item
		}
	}

	return output, nil
}
